package com.averroes.classifiers
{
	import mx.utils.ArrayUtil;
	import com.averroes.*;
			
	/**
	 * A rule-based gesture classifier
	 * @author marram
	 * 
	 */	
	public class GestureClassifier
	{
		public static function getCriticalPoints(gesture:Gesture, speed_threshold:Number=0.7):Array
		{				
			var dx:Array = Calculus.diff(gesture.xs);
			var dy:Array = Calculus.diff(gesture.ys);
				
			var criticalx:Array = ArrayUtils.find(dx, 0);
			var criticaly:Array = ArrayUtils.find(dy, 0);
				
			var critical:Array = ArrayUtils.array_intersect(criticalx, criticaly, 2);
			critical.sort();
				
			critical = ArrayUtils.array_unique(critical);

			return critical;
		}
		
		public static function getSpeedCorners(gesture:Gesture, speed_threshold:Number=0.5):Array
		{
			var avgSpeed:Number = Statistics.mean(gesture.penSpeeds);
			var speedCandidatePoints:Array = ArrayUtils.findLessThanOrEqual(gesture.penSpeeds, speed_threshold*avgSpeed);
			return mergeCandidatePoints(speedCandidatePoints, 6);			
		}
		
		public static function getCurvaturePoints(gesture:Gesture, c_threshold:Number):Array
		{
			var curvature:Array = gesture.calculateCurvature(8);
			//var dC:Array = Calculus.diff(curvature);
			var points:Array = ArrayUtils.findGeq(ArrayUtils.abs(curvature), c_threshold);
			return points;
		}
		
		public static function getAllPoints(gesture:Gesture, c_threshold:Number, speed_threshold:Number):Array
		{
			var speedPoints:Array = 	GestureClassifier.getSpeedCorners(gesture);
			var curvPoints:Array = 		GestureClassifier.getCurvaturePoints(gesture, Number(cThreshold.text));
			var criticalPoints:Array = 	GestureClassifier.getCriticalPoints(gesture);
			
			//merge
			var pointIndices:Array = ArrayUtils.array_unique(ArrayUtils.array_combine(ArrayUtils.array_combine(speedPoints, curvPoints), criticalPoints));
			pointIndices.sort(Array.NUMERIC);
			var mergedIndices:Array = GestureClassifier.mergeCandidatePoints(pointIndices, 2);			
		}

		
		public static function mergeCandidatePoints(points:Array, tolerance:int):Array
		{
			var ret:Array = new Array();
			//make a copy of the points array
			var points_copy:Array = points.slice();
			var derivative:Array = Calculus.diff(points_copy);
			var segments:Array = new Array();
			segments.push(0);
			
			for (var i:int =0; i<derivative.length; i++)
				if (derivative[i] > tolerance)
					segments.push(i+1);
			var last:int = points.length -1;
			if (-1 == segments.lastIndexOf(last))
				segments.push(last);
					
			if (segments.length > 0)
			{
				for (i=1; i<segments.length; i++)
					ret.push(Math.floor(Statistics.mean(points_copy.slice(segments[i-1], segments[i]))));
			}
				
			
			
			/*
			for (var merge_window:int=4; merge_window<=6; merge_window++)
			{
				for (var j:int=0; j<=(points_copy.length - merge_window); j++)
				{
					var slice:Array = points_copy.slice(j, j+merge_window);
					if (Statistics.std(slice) <= tolerance)
					{
						points_copy = ArrayUtils.array_remove_slice(points_copy, j, j+merge_window);
					}
					else
					{
						ret.push(Math.floor(Statistics.mean(slice)));
					}
				}		
			}	
			return ret;
			*/
			return ret;
		}	
	}
}